home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!cs.odu.edu!Amiga-Request
- From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
- Newsgroups: comp.sources.amiga
- Subject: v90i041: BBSindex 1.0 - file database utility for BBS-PC!, Part01/03
- Message-ID: <11248@xanth.cs.odu.edu>
- Date: 2 Feb 90 19:55:18 GMT
- Sender: tadguy@cs.odu.edu
- Reply-To: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
- Lines: 2081
- Approved: tadguy@cs.odu.edu (Tad Guy)
- X-Mail-Submissions-To: Amiga@cs.odu.edu
-
- Submitted-by: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
- Posting-number: Volume 90, Issue 041
- Archive-name: util/bbsindex-1.0/part01
-
- BBSindex is a utility for use with the BBS-PC! bulletin board package. It
- allows you to list the contents of the file database in a wide variety
- of ways. It has its own script language with 20 commands which allows a
- wide variety of tasks to be performed.
-
- Eddy Carroll ecarroll@vax1.tcd.ie
-
- #!/bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 3)."
- # Contents: scripts scripts/bbsindex.scr scripts/filenote.scr
- # scripts/info.scr scripts/move.scr scripts/offline.scr src
- # src/bbs.h src/bbsindex.h src/checkfiles.c src/expression.c
- # src/makefile src/sort.c src/system.h src/tiny.a
- # Wrapped by tadguy@xanth on Fri Feb 2 14:54:35 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test ! -d 'scripts' ; then
- echo shar: Creating directory \"'scripts'\"
- mkdir 'scripts'
- fi
- if test -f 'scripts/bbsindex.scr' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'scripts/bbsindex.scr'\"
- else
- echo shar: Extracting \"'scripts/bbsindex.scr'\" \(2360 characters\)
- sed "s/^X//" >'scripts/bbsindex.scr' <<'END_OF_FILE'
- X#
- X# This script builds sorted file catalogues for the Amiga and IBM
- X# file areas (i.e. sections 3, 4, 6 and 1), on the Infomatique BBS
- X# (Phone: Dublin 302970 (+353-1-302970), V21/22bis/23)
- X#
- X# The following constants define the output files for the various filelists
- X# Change them to suit.
- X
- XAmigaFiles = "Amiga.Files"
- XIBMFiles = "IBM.Files"
- X
- X#
- X# This macro outputs the header for a filelist
- X#
- Xmacro header # SectionNumber, No. of dirs, SectionName, Filename
- X select Section = $1
- X scan
- X echo "Sorted list of $3 files - %d %w %t"
- X echo ""
- X echo "This file is available in the files section as $4"
- X echo "Files which are not currently available are marked with a *"
- X echo ""
- X echo "Total of %n files in $2 sections, occupying %m Megabytes."
- X echo ""
- Xendm
- X
- X#
- X# This macro takes a Section, Directory and title, and produces a list of
- X# all the files in that section and directory.
- X#
- Xmacro sublist # Section, Directory, Title
- X echo "%{$2. $3}\n%u-"
- X select Section = $1 AND Directory = $2
- X list
- X echo ""
- Xendm
- X
- X#
- X# Standard file stuff, the same for everything
- X#
- Xnorequest
- Xcheckfiles
- Xformat "%15n %w %-6x-%b{B,T}%v{ ,*} %c"
- Xsort Section, Directory, Name
- X
- X#
- X# List Amiga files
- X#
- Xopen $(AmigaFiles)
- Xheader 3, 14, "Amiga", "AMIGA.FILES"
- Xsublist 3, 1, "General text files"
- Xsublist 3, 2, "Technical text files"
- Xsublist 3, 3, "Archived text files"
- Xsublist 3, 4, "Games"
- Xsublist 3, 5, "Screen Hacks"
- Xsublist 3, 6, "Graphics, sound & demos"
- Xsublist 3, 7, "Graphics & sound programs"
- Xsublist 3, 8, "DOS utilities"
- Xsublist 3, 9, "Programming utilities"
- Xsublist 3, 10, "Resident utilities "
- Xsublist 3, 11, "Applications"
- Xsublist 3, 12, "Comms programs"
- Xsublist 3, 13, "Miscellaneous"
- Xsublist 3, 14, "Hardware"
- X#
- X# List IBM files
- X#
- Xopen $(IBMfiles)
- Xheader 4, 16, "IBM", "IBM.FILES"
- Xsublist 4, 1, "General, Miscellaneous"
- Xsublist 4, 2, "Miscellaneous Text Files"
- Xsublist 4, 3, "Digestives"
- Xsublist 4, 4, "DOS File Utilities"
- Xsublist 4, 5, "Archive Utilities"
- Xsublist 4, 6, "Pop-Up Utilities"
- Xsublist 4, 7, "Games & Fun"
- Xsublist 4, 8, "Graphics Progs"
- Xsublist 4, 9, "Graphics Images & Viewers"
- Xsublist 4, 10, "Sound & Music"
- Xsublist 4, 11, "Source Code & Programming"
- Xsublist 4, 12, "Viruses"
- Xsublist 4, 13, "Comms Packages & Utils"
- Xsublist 4, 14, "Mainstream Applications"
- Xsublist 4, 15, "Education/Tutorials"
- Xsublist 4, 16, "Hardware Utils, Performance Tests"
- END_OF_FILE
- if test 2360 -ne `wc -c <'scripts/bbsindex.scr'`; then
- echo shar: \"'scripts/bbsindex.scr'\" unpacked with wrong size!
- fi
- # end of 'scripts/bbsindex.scr'
- fi
- if test -f 'scripts/filenote.scr' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'scripts/filenote.scr'\"
- else
- echo shar: Extracting \"'scripts/filenote.scr'\" \(511 characters\)
- sed "s/^X//" >'scripts/filenote.scr' <<'END_OF_FILE'
- X#
- X# This script generates an AmigaDOS batch file to go through all the
- X# files on the system and add a filenote to them, giving the following
- X# information:
- X#
- X# (Section, Directory) BBS Filename Uploader File description
- X#
- X
- XOpen "filenote.exec"
- X
- Xnorequest
- Xcheckfiles
- X
- Xselect Online
- X
- Xformat 'filenote %f "%6{(%s,%r)} %15n %15o %c"'
- Xecho ";"
- Xecho "; Batchfile to add comments to all the BBS files in the system
- Xecho ";"
- Xlist
- Xecho ";"
- Xecho 'echo "Total of %n files successfully filenoted"'
- Xecho ";"
- END_OF_FILE
- if test 511 -ne `wc -c <'scripts/filenote.scr'`; then
- echo shar: \"'scripts/filenote.scr'\" unpacked with wrong size!
- fi
- # end of 'scripts/filenote.scr'
- fi
- if test -f 'scripts/info.scr' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'scripts/info.scr'\"
- else
- echo shar: Extracting \"'scripts/info.scr'\" \(806 characters\)
- sed "s/^X//" >'scripts/info.scr' <<'END_OF_FILE'
- X###########################################################################
- X#
- X# This simple script file merely prints all possible information about
- X# each file in the catalogue. It serves as a good demonstration of how
- X# to use extended command lines. Practically the whole script is a single
- X# extended format command!
- X#
- X###########################################################################
- X
- Xnorequest
- Xcheckfiles
- X
- Xformat "\
- XFilename : %n\n\
- XUploaded by : %o\n\
- XComment : %c\n\
- XFiletype : %b{Binary,Text}\n\
- XDisk filename : %f\n\
- XOrigin : %l{Local, Remote}\n\
- XStatus : %i{Online, Offline}\n\
- XFile state : %v{Valid, Invalid}\n\
- XAccesses : %a\n\
- XSection : %s\n\
- XDirectory : %r\n\
- XUpload date : %w\n\
- XFile size : %x\n\
- X----------"
- Xsort name
- Xlist
- END_OF_FILE
- if test 806 -ne `wc -c <'scripts/info.scr'`; then
- echo shar: \"'scripts/info.scr'\" unpacked with wrong size!
- fi
- # end of 'scripts/info.scr'
- fi
- if test -f 'scripts/move.scr' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'scripts/move.scr'\"
- else
- echo shar: Extracting \"'scripts/move.scr'\" \(1001 characters\)
- sed "s/^X//" >'scripts/move.scr' <<'END_OF_FILE'
- X#
- X# Simple script to generate and execute an AmigaDOS batch file to move
- X# all the files in a particular section into # a new common directory.
- X#
- X
- X#
- X# Set the output file, destination directory and section no's appropriately.
- X#
- X
- XOutFile = "Move.exec"
- XDest = "DH1:Somedirectory"
- XSection = 3
- X
- X#
- X# Use the following MV definition if you have a MV that supports moves
- X# across disk boundaries (such as Edwin Hoogerbeets' excellent one).
- X#
- X
- XMV = "mv %f $(Dest)"
- X
- X#
- X# Use the following MV definition if you want to use plain AmigaDOS
- X#
- X
- X# MV = "copy %f $(Dest)\ndelete $f"
- X
- X#
- X# Now generate the list of files. We sort by directory name to try
- X# and localise disk access
- X#
- X
- Xformat "$(MV)"
- XNoRequest
- XCheckFiles
- XSelect Online and Section = $(Section)
- XSort Diskname
- Xecho ";"
- Xecho "; BBSindex generated AmigaDOS batch file to move files in"
- Xecho "; section $(Section) to directory $(Dest)."
- Xecho ";"
- Xecho "; Created on %d %w %r"
- Xecho ";"
- Xlist
- Xecho ";"
- Xecho 'Echo "Total of %n files moved successfully"'
- Xecho ";"
- END_OF_FILE
- if test 1001 -ne `wc -c <'scripts/move.scr'`; then
- echo shar: \"'scripts/move.scr'\" unpacked with wrong size!
- fi
- # end of 'scripts/move.scr'
- fi
- if test -f 'scripts/offline.scr' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'scripts/offline.scr'\"
- else
- echo shar: Extracting \"'scripts/offline.scr'\" \(847 characters\)
- sed "s/^X//" >'scripts/offline.scr' <<'END_OF_FILE'
- X##############################################
- X#
- X# This script lists all the files in the
- X# BBS catalogue that are offline or invalid
- X#
- X##############################################
- X
- Xnorequest
- Xcheckfiles
- Xsort Section, Name
- Xformat "%s:%15n %-6x-%b{B,T} | %15d\n%28{} | %c"
- X
- Xecho ""
- Xecho "BBS-PC! file report - %d %w %t"
- Xecho ""
- X
- X##############################################
- X#
- X# List offline files
- X#
- X##############################################
- X
- Xselect Offline
- Xecho "%{Files offline}\n%u-"
- Xlist
- Xecho ""
- Xecho "(Total of %n files offline.)"
- Xecho ""
- X
- X##############################################
- X#
- X# List invalid files
- X#
- X##############################################
- X
- Xselect Online and Invalid
- Xecho "%{Files online, but possibly corrupt}\n%u-"
- Xlist
- Xecho ""
- Xecho "(Total of %n files possibly corrupt.)"
- Xecho ""
- Xecho ""
- END_OF_FILE
- if test 847 -ne `wc -c <'scripts/offline.scr'`; then
- echo shar: \"'scripts/offline.scr'\" unpacked with wrong size!
- fi
- # end of 'scripts/offline.scr'
- fi
- if test ! -d 'src' ; then
- echo shar: Creating directory \"'src'\"
- mkdir 'src'
- fi
- if test -f 'src/bbs.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/bbs.h'\"
- else
- echo shar: Extracting \"'src/bbs.h'\" \(3354 characters\)
- sed "s/^X//" >'src/bbs.h' <<'END_OF_FILE'
- X/*
- X * Standard BBS-PC! headers (with a few modifications)
- X *
- X * Important note: This header file cannot be precompiled with
- X * Lattice C V5.02, because of a bug which prevents bit fields
- X * from working properly when they are precompiled.
- X */
- X
- X/* Official Micro-Systems Software Structures */
- X
- X#define NUM_TERM 10 /* Number of computer types */
- X#define NUM_SECT 16 /* Number of section names */
- X
- X#define CAT_LEN 15 /* File catalogue name lengths */
- X#define DESC_LEN 40 /* File catalogue desc length */
- X#define FNAME_LEN 12 /* File name lengths */
- X#define FPATH_LEN 30 /* File name path lengths */
- X#define NAME_LEN 24 /* User name length */
- X#define PASS_LEN 10 /* User password length */
- X#define SECT_LEN 20 /* Section name lengths */
- X#define TERM_LEN 15 /* Computer name lengths */
- X
- X/* UDHEAD.DAT record structure */
- X
- X/* Note some new additions to this structure, for internal tracking */
- X
- Xtypedef struct {
- X BYTE type;
- X int local:1; /* True if local upload */
- X int bin:1; /* True if binary file */
- X int valid:1; /* True if valid NEW */
- X int online:1; /* True if file online NEW */
- X int dirnum:5; /* Real dir num of file NEW */
- X int :7; /* Reserved CHANGED */
- X char cat_name[CAT_LEN]; /* Catalog filename (key1) */
- X UWORD date; /* Upload date serial */
- X BYTE dir; /* Dir number (key2 - seg1) */
- X BYTE section; /* Section number (key2 - seg2) */
- X UWORD accesses; /* Number of accesses */
- X LONG length; /* File length */
- X char disk_name[FNAME_LEN+1]; /* Disk filename */
- X char owner[NAME_LEN+1]; /* Owner's name */
- X char desc[DESC_LEN+1]; /* Description text */
- X} UDHEAD;
- X
- X#define UDSIZE sizeof(UDHEAD)
- X
- X
- X/* Terminal parameters */
- X
- Xtypedef struct {
- X int linefeed: 1;
- X int :31;
- X BYTE nuls;
- X BYTE protocol;
- X BYTE align;
- X BYTE page[2];
- X BYTE cls[4];
- X BYTE bs[3];
- X char name[TERM_LEN+1];
- X} TRMNL;
- X
- X
- X/* CFGINFO.DAT record structure */
- X
- Xtypedef struct {
- X int dir0_ok: 1; /* Directory 0 downloads */
- X int by_call: 1; /* Time limit per call */
- X short max_msg; /* Maximum messages in system */
- X short max_user; /* Maximum users in system */
- X short max_log; /* Maximum call log */
- X short max_ud; /* Maximum U/D files */
- X short reward; /* Upload reward */
- X short sleeptime; /* sleep timeout (adjusted) */
- X long dummy; /* Reserved */
- X BYTE log_p1; /* Log privilege low */
- X BYTE log_p2; /* Log privilege high */
- X BYTE hi_men; /* Highest menu set */
- X BYTE log_type; /* Login method */
- X short limit[2]; /* Guest/member time limits */
- X short priv[2]; /* Guest/member privileges */
- X UWORD rd_acc[2]; /* Guest/member read access */
- X UWORD wr_acc[2]; /* Guest/member write access */
- X UWORD up_acc[2]; /* Guest/member upload access */
- X UWORD dn_acc[2]; /* Guest/member download access */
- X BYTE sav_sec[2]; /* Guest/member save section */
- X BYTE sec_flg[NUM_SECT]; /* Section flags */
- X char sec_name[NUM_SECT] [SECT_LEN+1]; /* Section names */
- X char ud_alt[NUM_SECT] [FPATH_LEN+1]; /* Alternate UD paths */
- X char syspass[PASS_LEN+1]; /* Sysop password */
- X BYTE menu[2]; /* Guest/Member menu sets */
- X BYTE align;
- X long dummy2;
- X long dummy3;
- X TRMNL trmnl[NUM_TERM]; /* Terminal parameters */
- X} CFGINFO;
- X
- X#define CFGSIZE sizeof(CFGINFO)
- END_OF_FILE
- if test 3354 -ne `wc -c <'src/bbs.h'`; then
- echo shar: \"'src/bbs.h'\" unpacked with wrong size!
- fi
- # end of 'src/bbs.h'
- fi
- if test -f 'src/bbsindex.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/bbsindex.h'\"
- else
- echo shar: Extracting \"'src/bbsindex.h'\" \(12473 characters\)
- sed "s/^X//" >'src/bbsindex.h' <<'END_OF_FILE'
- X/*
- X * BBSINDEX.H
- X *
- X * All the standard variables and other stuff used by all the modules
- X * of BBSindex, and standard BBS-PC! headers (with a few modifications).
- X *
- X * Important note: This header file cannot be precompiled with
- X * Lattice C V5.02, because of a bug which prevents bit fields
- X * from working properly when they are precompiled.
- X */
- X
- X#include "bbs.h"
- X
- X#define TRUE 1
- X#define FALSE 0
- X
- X#define BTOK(x) (((x)+1023)>>10) /* Convert file size into K */
- X
- X/*
- X * Default values for command line parameters and script commands
- X */
- X
- X#define FORMAT "%15n %w %-6x-%b{B,T} %c\n"
- X#define UDNAME "UDHEAD.DAT"
- X#define CFGNAME "CFGINFO.DAT"
- X#define PROGSCRIPT "BBSCRIPT"
- X#define DEFSCRIPT "BBSindex.scr"
- X
- X/*
- X * Blocksize determines the largest contiguous memory segment which is
- X * needed. Larger values give faster processing, but need more continuous
- X * memory.
- X */
- X
- X#define BLOCKSIZE 160 /* Number of records/block (~16K) */
- X#define MAXOUT 1024 /* The maximum length of an output line */
- X#define MAXCOM 1024 /* Maximum size of a single command */
- X#define MAXSUB 256 /* Maximum size of a sub format string */
- X#define FRAGBLOCK 8192 /* Memory block to allocate in mymalloc */
- X#define FRAGTHRESH 200 /* Threshold for mem reqs in mymalloc */
- X#define BUFSIZE 8192 /* Maximum size of output buffer */
- X#define MAXEXPR 100 /* Max number of items in an expression */
- X#define MAXDIRENT 1000 /* Maximum number of unknown dir files */
- X#define DIRFRAG 100 /* Number of dir entries/block alloced */
- X#define DIRNAMESIZE 80 /* Maximum length of directory name */
- X#define MACROLEN 20 /* Maximum length of macro name */
- X#define MAXMACRO 50 /* Maximum number of macros allowed */
- X#define MAXNEST 10 /* Max number of macro nesting levels */
- X#define MAXCONST 20 /* Maximum length of a constant name */
- X
- X/* Note: MAXSUB above is allocated on the stack, so don't make it too big */
- X
- X/*
- X * This structure is used to build a tree structure representing
- X * the expression given with the SELECT command.
- X */
- Xstruct expr {
- X int field; /* Field to test, or boolean operator */
- X int op; /* Operator to test against, if any */
- X int num; /* First data field */
- X char *text; /* Second data field */
- X struct expr *left; /* Left subtree */
- X struct expr *right; /* Right subtree */
- X};
- X
- Xtypedef struct expr EXPR;
- X
- X/*
- X * This structure is used to hold the name of a file found in
- X * a BBS-PC! file directory during CHECKFILES, which does not
- X * exist in the BBS-PC! file catalogue.
- X */
- Xtypedef struct {
- X char name[32]; /* Disk filename */
- X short date; /* In BBS-PC! format, max 16 bits */
- X short dirnum; /* The directory number it was in */
- X long size; /* The size of the file, in bytes */
- X} DIRENTRY;
- X
- X#define DIRENTRYSIZE sizeof(DIRENTRY)
- X
- X/*
- X * This structure holds the names of files to be "ignored" during a
- X * CHECKFILES. I.e. they are marked as valid, even if their filesize
- X * on disk doesn't match that in the file catalogue. This structure
- X * is built up with the IGNORE command.
- X */
- Xstruct ignore {
- X struct ignore *next;
- X char name[CAT_LEN+1];
- X};
- X
- Xtypedef struct ignore IGNORE;
- X
- X/*
- X * This structure is used to store macro definitions. Note that
- X * a single block is used to store both the macro and its definition.
- X * The structure is dynamically sized at runtime, to fit whatever
- X * size definition is given. The text[] array (nominally 1) gets
- X * expanded to hold the definition.
- X */
- Xtypedef struct {
- X char name[MACROLEN]; /* Name of this macro */
- X int size; /* Size of macro text */
- X char text[1]; /* Start of macro text */
- X} MACRO;
- X
- X#define MACROSIZE (sizeof(MACRO) - 1) /* The -1 is for text[1] */
- X
- X/*
- X * This structure holds a block of parameters for a macro that is
- X * executing.
- X */
- Xtypedef struct {
- X int size; /* Size of parameter block */
- X char params[1]; /* Start of parameter block */
- X} PARAM;
- X
- X#define PARAMSIZE (sizeof(PARAM) - 1) /* The -1 is for params[1] */
- X
- X
- X/*
- X * This macro checks to make sure that the file database has been
- X * read in. This is delayed until as late as possible, so that if
- X * the script file contains errors, the errors will be spotted BEFORE
- X * the database is read in. The primary goal here is to save the user
- X * having to wait for 200K or so of database to be read in, just so
- X * they can see they have an error in their script. Instead, the
- X * database is only read in when a command cannot execute without
- X * having access to the files. Such commands are SORT, SCAN, LIST,
- X * CHECKFILES and FOREIGN.
- X */
- X#define CHECKDATABASE() {if (!readfiles) readdatabase(databasename);}
- X
- X/*
- X * Global variables, accessible to all modules
- X */
- X
- X#ifdef GLOBAL
- X#undef GLOBAL
- X#endif
- X#ifdef MAIN
- X#define GLOBAL
- X#else
- X#define GLOBAL extern
- X#endif
- X
- XGLOBAL char *script; /* Array for storing the script */
- XGLOBAL long scriptsize; /* The size of the current script */
- XGLOBAL long scriptpos; /* Position in the current script */
- XGLOBAL long linenum; /* Line number in script file */
- XGLOBAL char out[MAXOUT]; /* Array for storing the output lines */
- XGLOBAL char combuf[MAXCOM]; /* Buffer to hold a single command */
- XGLOBAL char formatstring[MAXCOM];/* Used to store the output format string */
- XGLOBAL char databasename[256]; /* The name of the BBS-PC! file database */
- XGLOBAL char configname[256]; /* The name of the BBS-PC! config file */
- XGLOBAL char scriptname[256]; /* The name of the current script file */
- XGLOBAL UDHEAD **ptrblock; /* Array of pointers to file records */
- XGLOBAL long numrecs; /* The number of file headers read in */
- XGLOBAL long compos; /* Position on the current command line */
- XGLOBAL long comlen; /* Length of current command line */
- XGLOBAL BPTR outfile; /* Output file (Default is stdout) */
- XGLOBAL BPTR errorfile; /* Standard error file (screen usually) */
- XGLOBAL BPTR dirlock; /* Lock used when scanning directories */
- XGLOBAL struct FileInfoBlock *fib;/* Global fib struct on longword boundary */
- XGLOBAL int checkfiles; /* TRUE if file directories were scanned */
- XGLOBAL int readfiles; /* TRUE if database file has been read in */
- XGLOBAL int toscreen; /* TRUE if output is to screen */
- XGLOBAL int totalbytes; /* Total number of bytes output so far */
- XGLOBAL int totalfiles; /* Total number of files output so far */
- XGLOBAL int curbytes; /* Number of bytes output by last LIST/SCAN */
- XGLOBAL int curfiles; /* Number of files output by last LIST/SCAN */
- XGLOBAL int sorted; /* True if file array has been sorted */
- XGLOBAL EXPR tree[MAXEXPR]; /* Array to hold parsed SELECT expression */
- XGLOBAL int numdirentries; /* Number of fake directory entries */
- XGLOBAL DIRENTRY *direntries[MAXDIRENT];/* Storage for ptrs to dir entries */
- XGLOBAL char dirnames[NUM_SECT][DIRNAMESIZE];/* Storage for directory names */
- XGLOBAL CFGINFO config[1]; /* BBS-PC! Configuration file structure */
- XGLOBAL MACRO *macros[MAXMACRO]; /* Array of ptrs to macro definitions */
- XGLOBAL int nummacros; /* Number of macros currently defined */
- XGLOBAL PARAM *params[MAXNEST]; /* Array of pointers to macro parameters */
- XGLOBAL int nestlevel; /* Current macro nest level */
- XGLOBAL int tracemode; /* Trace mode; TRUE if tracing enabled */
- XGLOBAL IGNORE *firstignore; /* Pointer to first filename to ignore */
- X
- X/*
- X * Global functions, accessible everywhere
- X */
- X
- Xchar *format(); /* Format output string from file header + format spec */
- Xchar *echoformat(); /* Formats output string for ECHO command */
- Xchar *itoa(); /* Convert integer into ASCII format */
- Xchar *getstring(); /* Get next string from command buffer */
- Xvoid *mymalloc(); /* Safe memory tracker that handles out of memory */
- Xvoid *SafeAllocMem();/* Safe AllocMem that handles out of memory */
- Xvoid execscript(); /* Executes all the commands in the current script */
- Xvoid Cleanup(); /* Frees resources and exits program */
- Xvoid chkabort(); /* Checks for Control-C, and aborts if detected */
- Xvoid putstring(); /* Outputs string to standard I/O */
- Xvoid flushout(); /* Flushes data buffer to output file */
- Xvoid parse(); /* Parse command line and build expression tree */
- Xvoid readdatabase();/* Reads in the BBS-PC! UDHEAD.DAT file database */
- Xvoid readconfigfile();/* Reads in the BBS-PC! CFGINFO.DAT file */
- Xvoid print(); /* Prints a string to stderr */
- Xvoid com_select(); /* SELECT, specifies criteria for files to select */
- Xvoid com_checkfiles();/* Scans file directories, updating catlague entries */
- Xvoid com_sort(); /* Sorts file catalogue into a particular order */
- Xvoid com_foreign(); /* Prints a list of all the unknown foreign files */
- Xvoid com_norequest();/* Stop AmigaDos from putting up requesters */
- Xint match(); /* Returns TRUE if record matches current selection */
- Xint scandir(); /* Scans directory for files, returns TRUE if continue */
- Xint sortcmp(); /* Internal routine used for sorting files */
- X
- X/*
- X * print3()
- X * --------
- X * Prints 3 strings to standard error
- X */
- X#define print2(s1,s2) (print(s1), print(s2))
- X#define print3(s1,s2,s3) (print(s1), print(s2), print(s3))
- X
- X/*
- X * The list of identifiers used by SORT and SELECT.
- X */
- X
- X#define MAXINDEX 16
- X
- X#define I_ANY 0
- X#define I_ACCESS 1
- X#define I_BINARY 2
- X#define I_COMMENT 3
- X#define I_DISKNAME 4
- X#define I_SECTION 5
- X#define I_ONLINE 6
- X#define I_LOCAL 7
- X#define I_NAME 8
- X#define I_OWNER 9
- X#define I_PATHNAME 10
- X#define I_DIRECTORY 11
- X#define I_DISKDIRNUM 12
- X#define I_VALID 13
- X#define I_DATE 14
- X#define I_SIZE 15
- X#define I_KSIZE 16
- X
- XGLOBAL struct {
- X int tag;
- X char *name;
- X} indexes[MAXINDEX]
- X#ifdef MAIN
- X= {
- X
- X{ I_ACCESS, "ACCESS"}, /* Number of times file was accessed */
- X{ I_BINARY, "BINARY"}, /* True if Binary, False if text */
- X{ I_COMMENT, "COMMENT"}, /* The file comment */
- X{ I_DISKNAME, "DISKNAME"}, /* The name of the file on disk */
- X{ I_SECTION, "SECTION"}, /* # of the section the file is in */
- X{ I_ONLINE, "ONLINE"}, /* True if file online */
- X{ I_LOCAL, "LOCAL"}, /* True if file uploaded locally */
- X{ I_NAME, "NAME"}, /* The name of the file in the catalog */
- X{ I_OWNER, "OWNER"}, /* The name of uploader of the file */
- X{ I_PATHNAME, "PATHNAME"}, /* Pathname to file on disk */
- X{ I_DIRECTORY, "DIRECTORY"}, /* # of directory file is in */
- X{ I_DISKDIRNUM, "DISKDIRNUM"}, /* # of disk directory file is in */
- X{ I_VALID, "VALID"}, /* True if file is Valid */
- X{ I_DATE, "DATE"}, /* The date the file was uploaded */
- X{ I_SIZE, "SIZE"}, /* The size of the file */
- X{ I_KSIZE, "KSIZE"} /* The size of the file in K */
- X}
- X#endif
- X;
- X
- XGLOBAL char *months[]
- X#ifdef MAIN
- X= {
- X "xxx",
- X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- X}
- X#endif
- X;
- X
- X/*
- X * Special characters that can occur in the script
- X */
- X#define CHAR_TAB '\t'
- X#define CHAR_SPACE ' '
- X#define CHAR_HASH '#'
- X#define CHAR_NL '\n'
- X#define CHAR_ESC '\\'
- X#define CHAR_QUOTE '\''
- X#define CHAR_QUOTES '\"'
- X#define CHAR_SEMI ';'
- X#define CHAR_COMMA ','
- X#define CHAR_EQUALS '='
- X#define CHAR_DOLLAR '$'
- X#define CHAR_NULL '\0'
- X
- X#define CHAR_ASCEND '+'
- X#define CHAR_DESCEND '-'
- X
- X/*
- X * The following symbols are used in the expression tree
- X */
- X
- X/*
- X * Boolean operations, which share storage with field selectors
- X */
- X
- X#define E_AND 30 /* <left> AND <right> */
- X#define E_OR 31 /* <left> OR <right> */
- X#define E_NOT 32 /* NOT <left> */
- X#define E_ALL 33 /* Always true */
- X
- X/*
- X * Comparison operators, used for comparing record elements
- X */
- X#define E_EQ 34 /* Record == Value */
- X#define E_NE 35 /* Record != Value */
- X#define E_LT 36 /* Record < Value */
- X#define E_GT 37 /* Record > Value */
- X#define E_LE 38 /* Record <= Value */
- X#define E_GE 39 /* Record >= Value */
- X
- X#define E_OPENPAR 40 /* Open parameter token */
- X#define E_CLOSEPAR 41 /* Close parameter token */
- X
- X#define E_NUMBER 42 /* Any numeric value */
- X#define E_STRING 43 /* Anything in quotes */
- X#define E_END 44 /* End of command line */
- X
- X#define E_TEXT 45 /* File is a text file */
- X#define E_REMOTE 46 /* File is a remote file */
- X#define E_INVALID 47 /* File is invalid */
- X#define E_OFFLINE 48 /* File is offline */
- X
- X
- X/*
- X * Wildcard special fields for strings
- X */
- X#define tokentowild(x) ((x)+50)
- X
- X#define W_OWNER tokentowild(I_OWNER)
- X#define W_NAME tokentowild(I_NAME)
- X#define W_DISKNAME tokentowild(I_DISKNAME)
- X#define W_COMMENT tokentowild(I_COMMENT)
- END_OF_FILE
- if test 12473 -ne `wc -c <'src/bbsindex.h'`; then
- echo shar: \"'src/bbsindex.h'\" unpacked with wrong size!
- fi
- # end of 'src/bbsindex.h'
- fi
- if test -f 'src/checkfiles.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/checkfiles.c'\"
- else
- echo shar: Extracting \"'src/checkfiles.c'\" \(6592 characters\)
- sed "s/^X//" >'src/checkfiles.c' <<'END_OF_FILE'
- X/*
- X * CHECKFILES.C
- X *
- X * This module contains routines to read in the disk directory, search
- X * the file database for each filename found to see if it matches, etc.
- X *
- X */
- X
- X#ifndef LATTICE_50
- X#include "system.h"
- X#endif
- X#include "bbsindex.h"
- X
- X/*
- X * addunknown()
- X * ------------
- X * Adds a new entry to the list of unknown files found. If necessary,
- X * more memory will be allocated to hold the new entry.
- X */
- Xint addunknown(name, size, date, dirnum)
- Xchar *name;
- Xlong size;
- Xint date, dirnum;
- X{
- X static DIRENTRY *dirbase, *dir;
- X
- X if (numdirentries >= MAXDIRENT) {
- X scripterror("directory table full. Skipping rest of files\n");
- X return (FALSE);
- X }
- X if ((numdirentries % DIRFRAG) == 0) /* Allocate new block */
- X dirbase = mymalloc(DIRENTRYSIZE * DIRFRAG);
- X
- X dir = &dirbase[numdirentries % DIRFRAG];
- X
- X strcpy(dir->name, name);
- X dir->size = size;
- X dir->date = date;
- X dir->dirnum = dirnum;
- X
- X direntries[numdirentries++] = dir;
- X return (TRUE);
- X}
- X
- X/*
- X * find()
- X * ------
- X * Does a binary search of the file records looking for the specified
- X * filename. Returns pointer to the file record if found, NULL if not
- X * found.
- X */
- XUDHEAD *find(name)
- Xchar *name;
- X{
- X long low = 0, high = numrecs -1;
- X long mid;
- X int cmp;
- X
- X while (high >= low) {
- X mid = (low + high) / 2;
- X cmp = stricmp(ptrblock[mid]->disk_name, name);
- X if (!cmp && ptrblock[mid]->type == 0) /* Found match */
- X return (ptrblock[mid]);
- X if (cmp > 0) /* Too far ahead, go backwards */
- X high = mid-1;
- X else /* Too far below, go forwards */
- X low = mid+1;
- X }
- X return (NULL);
- X}
- X
- X/*
- X * scandir()
- X * ---------
- X * Scans directory, adding the files found either to the 'unknown'
- X * list or updating the pointers in the main file database appropriately.
- X */
- Xint scandir(dirname, dirnum)
- Xchar *dirname;
- Xint dirnum;
- X{
- X UDHEAD *f;
- X struct tm *filedate;
- X int bbspcdate;
- X
- X dirlock = Lock(dirname, ACCESS_READ);
- X if (dirlock == NULL) {
- X scripterror("can't find directory ");
- X print2(dirname, ", skipping\n");
- X return (TRUE);
- X }
- X
- X if (!Examine(dirlock, fib)) {
- X scripterror("can't examine directory ");
- X print2(dirname, ", skipping\n");
- X UnLock(dirlock);
- X dirlock = NULL;
- X return (TRUE);
- X }
- X
- X while (ExNext(dirlock, fib)) {
- X chkabort();
- X if (fib->fib_DirEntryType > 0) /* Skip over directories */
- X continue;
- X if (f = find(fib->fib_FileName)) {
- X f->online = 1;
- X f->valid = (fib->fib_Size == f->length);
- X f->dirnum = dirnum;
- X } else {
- X /*
- X * Convert AmigaDOS date (# days since 1/1/78, # mins
- X * since midnight) into ANSI date (# seconds since 1/1/70)
- X * then convert that into BBS-PC! format.
- X */
- X long ansidate;
- X ansidate = (fib->fib_Date.ds_Days + (365 * 8) + 2) * 86400;
- X filedate = gmtime(&ansidate);
- X bbspcdate = (((filedate->tm_year * 13) +
- X (filedate->tm_mon+1)) * 32) +
- X filedate->tm_mday;
- X if (!addunknown(fib->fib_FileName, fib->fib_Size, bbspcdate,
- X dirnum)) {
- X UnLock(dirlock);
- X dirlock = NULL;
- X return (FALSE);
- X }
- X
- X }
- X }
- X if (IoErr() != ERROR_NO_MORE_ENTRIES) {
- X scripterror("error reading directory ");
- X print2(dirname, ", skipping\n");
- X }
- X UnLock(dirlock);
- X dirlock = NULL;
- X return (TRUE);
- X}
- X
- X/*
- X * diskcmp()
- X * ---------
- X * Compares the disk filenames of two file headers, and returns true
- X * if they are equal. Used by the sort routine in check_files().
- X */
- Xint diskcmp(f1,f2)
- XUDHEAD **f1, **f2;
- X{
- X return (stricmp((*f1)->disk_name, (*f2)->disk_name));
- X}
- X
- X/*
- X * com_checkfiles()
- X * ----------------
- X * This command scans the file directories specified on the command
- X * line (or if none, then using those specified in the CFGINFO.DAT
- X * file). Each file in the catalogue is searched for in the file
- X * catalogue, and those that are found are marked as "Online"; if
- X * the disk filesize matches the catalogue filesize, then their
- X * "valid" flag is also set. Files which are not found are stored
- X * in a seperate array, which can be printed with the FOREIGN command.
- X * After this, any other files listed in the IGNORE list are also marked
- X * as valid.
- X *
- X * Note that before the scan, the files are sorted into alphabetical
- X * order, by diskname, to allow a binary search to be done. Afterwards,
- X * if this disrupted a previous sorting order, they are sorted back
- X * to their original state.
- X */
- Xvoid com_checkfiles()
- X{
- X int dirnum;
- X IGNORE *ig;
- X UDHEAD *f;
- X
- X if (checkfiles)
- X return;
- X
- X CHECKDATABASE();
- X qsort(ptrblock, numrecs, sizeof(UDHEAD *), diskcmp);
- X if (compos >= comlen) {
- X readconfigfile();
- X for (dirnum = 0; dirnum < NUM_SECT && dirnames[dirnum][0]; dirnum++) {
- X chkabort();
- X if (!scandir(dirnames[dirnum], dirnum))
- X break;
- X }
- X } else {
- X for (dirnum = 0; dirnum < NUM_SECT; dirnum++) {
- X if (compos >= comlen)
- X break;
- X strcpy(dirnames[dirnum], getstring());
- X chkabort();
- X if (!scandir(dirnames[dirnum], dirnum))
- X break;
- X }
- X }
- X /*
- X * Now mark any "ignored" files as valid.
- X */
- X for (ig = firstignore; ig; ig = ig->next) {
- X if (f = find(ig->name))
- X f->valid = 1;
- X }
- X chkabort();
- X if (sorted)
- X qsort(ptrblock, numrecs, sizeof(UDHEAD *), sortcmp);
- X checkfiles = TRUE;
- X}
- X
- X/*
- X * com_foreign()
- X * -------------
- X * This command prints out the list of foreign files, i.e. files
- X * not in the catalogue, using the format string setup with
- X * FORMAT. Not all fields are valid.
- X */
- Xvoid com_foreign()
- X{
- X /*
- X * Standard file header template for foreign files.
- X * Note file[] is an array, so we can say file->x instead of file.x
- X */
- X static UDHEAD file[1] = {{
- X 0, /* Record type (== valid) */
- X 1, 1, 1, 1, /* Local, Binary, Valid and Online :-) */
- X 0, /* Directory number is set later */
- X "", /* Catalogue filename, filled in later */
- X 0, /* Date is set later */
- X 0, 0, 0, /* Section 0, Directory 0, no accesses */
- X 0, /* Length is set later */
- X "", /* Disk name is set later */
- X "AmigaDos", /* The file owner */
- X "Directory = ", /* File comment, set later */
- X }};
- X
- X int i;
- X
- X if (!checkfiles) {
- X scripterror("can't do FOREIGN before CHECKFILES\n");
- X Cleanup(10);
- X }
- X
- X for (i = 0; i < numdirentries; i++) {
- X chkabort();
- X /* Setup actual file parameters for format() */
- X strcpy(file->disk_name, direntries[i]->name);
- X strncpy(file->cat_name, direntries[i]->name, CAT_LEN);
- X strncpy(file->desc+12, dirnames[direntries[i]->dirnum], DESC_LEN-12);
- X file->desc[DESC_LEN] = CHAR_NULL;
- X file->length = direntries[i]->size;
- X file->date = direntries[i]->date;
- X file->dirnum = direntries[i]->dirnum;
- X format(out, MAXOUT, formatstring, file, checkfiles);
- X putstring(out);
- X }
- X}
- END_OF_FILE
- if test 6592 -ne `wc -c <'src/checkfiles.c'`; then
- echo shar: \"'src/checkfiles.c'\" unpacked with wrong size!
- fi
- # end of 'src/checkfiles.c'
- fi
- if test -f 'src/expression.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/expression.c'\"
- else
- echo shar: Extracting \"'src/expression.c'\" \(11470 characters\)
- sed "s/^X//" >'src/expression.c' <<'END_OF_FILE'
- X/*
- X * EXPRESSION.C
- X *
- X * This module contains the routines needed to parse and evaluate an
- X * expression. This is used while selecting which files to print.
- X *
- X * This is the BNF for the set of expressions recognised by the
- X * database searcher. It doesn't contain any semantic information however.
- X *
- X * Expression ::= Boolean | Boolean Operator Expression | ALL
- X * Operator ::= AND | OR
- X * Boolean ::= NOT Boolean |
- X * '(' Expression ')' |
- X * BoolIdent |
- X * NumIdent Op Value |
- X * StringIdent Op String |
- X * DateIdent Op Date
- X * Op ::= '<' | '>' | '<=' | '>=' | '=' | '<>'
- X * BoolIdent ::= BINARY | ONLINE | LOCAL | VALID
- X * StringIdent ::= COMMENT | DISKNAME | NAME | OWNER | PATHNAME
- X * NumIdent ::= ACCESS | SECTION | DIRECTORY | DISKDIRNUM |
- X * SIZE | KSIZE
- X * DateIdent ::= DATE
- X * String ::= (Text enclosed in quotes)
- X * Value ::= (A number)
- X * Date ::= (A date in the format "dd-mon-yy")
- X *
- X */
- X
- X#ifndef LATTICE_50
- X#include "system.h"
- X#endif
- X
- X#include "bbsindex.h"
- X
- X#define mystrcmp stricmp /* Make match() insensitive to case */
- X
- X/*
- X * BNF procedures
- X */
- X
- Xvoid bnf_op(), bnf_date(), bnf_expression(), bnf_boolean();
- X
- X/*
- X * Global variable(s)
- X */
- X
- Xstatic int treepos; /* Next free entry in tree array */
- Xstatic int curtoken; /* Current token */
- Xstatic int curvalue; /* Current number with E_NUMBER */
- Xstatic char curstring[MAXCOM]; /* Current string with E_STRING */
- X
- X/*
- X * Tokens recognised as special in expressions
- X */
- X
- Xstruct {
- X int tag;
- X char *name;
- X} tokens[] = {
- X
- X { E_EQ, "=" },
- X { E_NE, "<>" },
- X { E_LE, "<=" },
- X { E_GE, ">=" },
- X { E_LT, "<" },
- X { E_GT, ">" },
- X { E_AND, "AND" },
- X { E_OR, "OR" },
- X { E_NOT, "NOT" },
- X { E_ALL, "ALL" },
- X { E_OPENPAR, "(" },
- X { E_CLOSEPAR, ")" },
- X { E_TEXT, "TEXT" },
- X { E_REMOTE, "REMOTE" },
- X { E_INVALID, "INVALID" },
- X { E_OFFLINE, "OFFLINE" },
- X { NULL, NULL }
- X};
- X
- X/*
- X * wild()
- X * ------
- X * This routine does a wildcard match on the two specified strings.
- X * The first string contains the string to check, and the second string
- X * containts the wildcard pattern to check against. The special wild
- X * card characters are '?' which matches any single characters, and
- X * '*' which matches any number of characters. 0 is returned if the
- X * the two strings match, else a +ve or -ve number.
- X *
- X */
- Xint wild(s,w)
- Xchar *s;
- Xchar *w;
- X{
- X char *p;
- X char ch;
- X
- X while (*w && *s) {
- X switch (*w) {
- X
- X case '*':
- X ch = toupper(w[1]);
- X if (!ch)
- X return (0);
- X for (p = s; *p; p++) {
- X if (toupper(*p) == ch || ch == '?') {
- X if (!wild(p,w+1))
- X return (0);
- X }
- X }
- X return (toupper(*p)-ch);
- X
- X case '?':
- X break;
- X
- X default:
- X if (toupper(*s) != toupper(*w))
- X return (toupper(*s)-toupper(*w));
- X }
- X w++;
- X s++;
- X }
- X return (toupper(*s)-toupper(*w));
- X}
- X
- X
- X/*
- X * Dirty great macro to compare two values according to an operator
- X */
- X#define e_cmp(v1,op,v2) \
- X switch (op) { \
- X case E_EQ: return ((v1) == (v2)); \
- X case E_NE: return ((v1) != (v2)); \
- X case E_LT: return ((v1) < (v2)); \
- X case E_GT: return ((v1) > (v2)); \
- X case E_LE: return ((v1) <= (v2)); \
- X case E_GE: return ((v1) >= (v2)); \
- X }
- X
- X#define e_numcmp(n) e_cmp(n, e->op, e->num)
- X#define e_strcmp(s) e_cmp(mystrcmp(s,e->text), e->op, 0)
- X#define e_wildcmp(s) e_cmp(wild(s,e->text), e->op, 0)
- X
- X/*
- X * match()
- X * -------
- X * Scans the the parse tree, and returns TRUE if the current
- X * record matches the criteria in the tree, else FALSE.
- X *
- X * Aside: Aren't C macros wonderful? Just think how long this function
- X * would be if it wasn't for the above e_cmp, e_numcmp and e_strcmp
- X * macros.
- X */
- Xint match(p, e)
- XUDHEAD *p;
- XEXPR *e;
- X{
- X switch (e->field) {
- X
- X case E_AND: return (match(p, e->left) && match(p, e->right));
- X case E_OR: return (match(p, e->left) || match(p, e->right));
- X case E_NOT: return (!match(p, e->left));
- X case E_ALL: return (TRUE);
- X case I_LOCAL: return ((int)p->local);
- X case I_BINARY: return ((int)p->bin);
- X case I_VALID: return ((int)p->valid);
- X case I_ONLINE: return ((int)p->online);
- X case E_REMOTE: return (!(int)p->local);
- X case E_TEXT: return (!(int)p->bin);
- X case E_INVALID: return (!(int)p->valid);
- X case E_OFFLINE: return (!(int)p->online);
- X case I_ACCESS: e_numcmp(p->accesses);
- X case I_DATE: e_numcmp(p->date);
- X case I_DIRECTORY: e_numcmp(p->dir);
- X case I_DISKDIRNUM: e_numcmp(p->dirnum);
- X case I_KSIZE: e_numcmp(BTOK(p->length));
- X case I_SECTION: e_numcmp(p->section);
- X case I_SIZE: e_numcmp(p->length);
- X case I_DISKNAME: e_strcmp(p->disk_name);
- X case I_COMMENT: e_strcmp(p->desc);
- X case I_NAME: e_strcmp(p->cat_name);
- X case I_OWNER: e_strcmp(p->owner);
- X case W_DISKNAME: e_wildcmp(p->disk_name);
- X case W_COMMENT: e_wildcmp(p->desc);
- X case W_NAME: e_wildcmp(p->cat_name);
- X case W_OWNER: e_wildcmp(p->owner);
- X }
- X}
- X
- X/*
- X * newnode()
- X * ---------
- X * This function allocates a new node from the tree array, and returns
- X * a pointer to it. If overflow occurs, it aborts with an error message.
- X */
- X
- XEXPR *newnode()
- X{
- X treepos++;
- X if (treepos >= MAXEXPR) {
- X scripterror("expression to complex\n");
- X Cleanup(10);
- X }
- X return (&tree[treepos]);
- X}
- X
- X/*
- X * readtoken()
- X * -----------
- X * This function reads the next token from the command line, starting
- X * at position curpos. curtoken is set to the type of token received.
- X * If it was E_STRING, then curstring points to the string it
- X * represents (without the quotes). If it was E_NUM, then curvalue
- X * points to the number represented. If the end of the line is
- X * reached, E_END is automatically set.
- X */
- X
- X#define nextch() (ch = combuf[compos++])
- X#define ungetnext() (compos--)
- X
- Xvoid readtoken()
- X{
- X char *p = curstring, ch;
- X int i;
- X
- X if (compos >= comlen) {
- X curtoken = E_END;
- X return;
- X }
- X
- X do {
- X nextch();
- X } while (ch == CHAR_SPACE);
- X
- X if (ch == CHAR_QUOTES) { /* Handle string in quotes */
- X curtoken = E_STRING;
- X nextch();
- X if (*p == CHAR_NULL) {
- X curtoken = E_END;
- X return;
- X }
- X do {
- X *p++ = ch;
- X nextch();
- X } while (ch && ch != CHAR_QUOTES);
- X *p = CHAR_NULL;
- X return;
- X }
- X
- X if (isdigit(ch)) { /* Numeric value? */
- X curtoken = E_NUMBER;
- X curvalue = 0;
- X do {
- X curvalue = curvalue * 10 + (ch - '0');
- X nextch();
- X } while (isdigit(ch));
- X ungetnext();
- X return;
- X }
- X
- X if (isalpha(ch)) { /* Alphabetic identifier? */
- X do {
- X *p++ = ch;
- X nextch();
- X } while (isalpha(ch));
- X } else if (ch == CHAR_NULL) { /* At end of line? */
- X curtoken = E_END;
- X return;
- X } else { /* Must be punctuation */
- X do {
- X *p++ = ch;
- X nextch();
- X } while (ch && !isalpha(ch) && !isdigit(ch) && ch != CHAR_SPACE
- X && ch != CHAR_QUOTES);
- X }
- X *p = CHAR_NULL;
- X ungetnext();
- X
- X /* Check for character A - F */
- X if (curstring[1] == CHAR_NULL) {
- X switch (curstring[0]) {
- X case 'A': case 'B': case 'C':
- X case 'D': case 'E': case 'F':
- X curvalue = curstring[0] + 10 - 'A';
- X curtoken = E_NUMBER;
- X return;
- X }
- X }
- X
- X /* Now find token that matches string */
- X for (i = 0; i < MAXINDEX; i++) {
- X if (!strcmp(curstring, indexes[i].name)) {
- X curtoken = indexes[i].tag;
- X return;
- X }
- X }
- X for (i = 0; tokens[i].name; i++) {
- X if (!strcmp(curstring, tokens[i].name)) {
- X curtoken = tokens[i].tag;
- X return;
- X }
- X }
- X scripterror("unrecognised symbol '");
- X print2(curstring,"' in expression\n");
- X Cleanup(10);
- X}
- X
- X
- X/*
- X * com_select()
- X * ------------
- X * This command parses the expression in the command buffer starting
- X * at position compos, and builds an expression tree representing it.
- X * This tree is stored in tree[], starting at element 0. This expression
- X * tree is used when match() is called.
- X */
- X
- Xvoid com_select()
- X{
- X treepos = 0;
- X readtoken();
- X bnf_expression(tree);
- X}
- X
- X/*
- X * bnf_expression()
- X * ----------------
- X * Parses the BNF line:
- X *
- X * Expression ::= Boolean | Boolean Operator Expression | ALL
- X *
- X */
- Xvoid bnf_expression(e)
- XEXPR *e;
- X{
- X EXPR dummy;
- X
- X if (curtoken == E_ALL)
- X e->field = E_ALL;
- X else {
- X bnf_boolean(&dummy);
- X if (curtoken == E_AND || curtoken == E_OR) {
- X e->field = curtoken;
- X e->left = newnode();
- X e->right = newnode();
- X *(e->left) = dummy;
- X readtoken();
- X bnf_expression(e->right);
- X } else
- X *e = dummy;
- X }
- X}
- X
- X/*
- X * bnf_boolean()
- X * -------------
- X * Parses the following BNF line:
- X *
- X * Boolean ::= NOT Boolean |
- X * '(' Expression ')' |
- X * BoolIdent |
- X * NumIdent Op Value |
- X * StringIdent Op String |
- X * DateIdent Op Date
- X */
- Xvoid bnf_boolean(e)
- XEXPR *e;
- X{
- X char *p;
- X
- X e->field = curtoken;
- X switch (curtoken) {
- X
- X case E_NOT:
- X e->left = newnode();
- X readtoken();
- X bnf_boolean(e->left);
- X break;
- X
- X case E_OPENPAR:
- X readtoken();
- X bnf_expression(e);
- X if (curtoken != E_CLOSEPAR) {
- X scripterror("missing close parenthesis\n");
- X Cleanup(10);
- X }
- X readtoken();
- X break;
- X
- X case I_BINARY:
- X case I_VALID:
- X case I_ONLINE:
- X case I_LOCAL:
- X case E_TEXT:
- X case E_INVALID:
- X case E_OFFLINE:
- X case E_REMOTE:
- X readtoken();
- X break;
- X
- X case I_ACCESS:
- X case I_SECTION:
- X case I_DIRECTORY:
- X case I_DISKDIRNUM:
- X case I_SIZE:
- X case I_KSIZE:
- X readtoken();
- X bnf_op(e);
- X if (curtoken != E_NUMBER) {
- X scripterror("number expected in expression\n");
- X Cleanup(10);
- X }
- X e->num = curvalue;
- X readtoken();
- X break;
- X
- X case I_COMMENT:
- X case I_DISKNAME:
- X case I_NAME:
- X case I_OWNER:
- X case I_PATHNAME:
- X readtoken();
- X bnf_op(e);
- X if (curtoken != E_STRING) {
- X scripterror("string expected in expression\n");
- X Cleanup(10);
- X }
- X e->text = mymalloc(strlen(curstring)+1);
- X strcpy(e->text, curstring);
- X /*
- X * Now check the string, and see if it contains any wildcard
- X * characters. If it does, use operation W_{string}
- X * instead of E_{string}. If it doesn't, use the standard
- X * strcmp which is much faster.
- X */
- X for (p = curstring; *p; *p++) {
- X if (*p == '*' || *p == '?') {
- X e->field = tokentowild(e->field);
- X break;
- X }
- X }
- X readtoken();
- X break;
- X
- X case I_DATE:
- X readtoken();
- X bnf_op(e);
- X bnf_date(e);
- X break;
- X
- X default:
- X scripterror("error in expression\n");
- X Cleanup(10);
- X }
- X}
- X
- X/*
- X * bnf_op
- X * ------
- X * Sets the operation field of the specified expression to the value
- X * of the next token on the command line.
- X */
- Xvoid bnf_op(e)
- XEXPR *e;
- X{
- X switch (curtoken) {
- X case E_EQ:
- X case E_NE:
- X case E_LT:
- X case E_GT:
- X case E_LE:
- X case E_GE:
- X e->op = curtoken;
- X readtoken();
- X break;
- X
- X default:
- X scripterror("expected comparison operator\n");
- X Cleanup(10);
- X }
- X}
- X
- X/*
- X * bnf_date()
- X * -----------
- X * Reads a date from the command line, validates it, and sets the
- X * 'num' field in the expression to its numerical value. The date
- X * is in the format "dd-mon-yy", e.g. "15-Jun-89"
- X */
- Xvoid bnf_date(e)
- XEXPR *e;
- X{
- X int day, month, year;
- X
- X if (curtoken != E_STRING) {
- X scripterror("expected date string in expression\n");
- X Cleanup(10);
- X }
- X
- X if (strlen(curstring) != 9 ||
- X curstring[2] != '-' || curstring[6] != '-') {
- X scripterror("Invalid date format (should be dd-mon-yy)\n");
- X Cleanup(10);
- X }
- X
- X day = atoi(curstring);
- X year = atoi(curstring+7);
- X for (month = 0; month < 12 && strnicmp(curstring+3, months[month], 3);
- X month++)
- X ;
- X if ((day < 1 || day > 31) || (month < 1 || month > 12) ||
- X (year < 1 || year > 99)) {
- X scripterror("Invalid date format (should be dd-mon-yy)\n");
- X Cleanup(10);
- X }
- X e->num = (((year * 13) + month) << 5) + day;
- X readtoken();
- X}
- END_OF_FILE
- if test 11470 -ne `wc -c <'src/expression.c'`; then
- echo shar: \"'src/expression.c'\" unpacked with wrong size!
- fi
- # end of 'src/expression.c'
- fi
- if test -f 'src/makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/makefile'\"
- else
- echo shar: Extracting \"'src/makefile'\" \(1075 characters\)
- sed "s/^X//" >'src/makefile' <<'END_OF_FILE'
- X#
- X# Lattice LKM makefile, for Lattice C V5.04
- X#
- X# BBSindex (C) Copyright Eddy Carroll, December 1989
- X#
- X
- X
- XCFLAGS = -cus -ms -j88i #-D3
- XOPT = -O
- X#BFLAGS = sc sd map ram:map addsym
- XBFLAGS = sc sd map ram:map nd
- XASM = lc:asm
- X#START = lib:catch.o
- XSTART = tiny.o
- X
- X.c.o:
- X lc $(CFLAGS) $(OPT) -Hsystem.sym $*.c
- X.a.o:
- X $(ASM) -isys:include/ -u $*.a
- X.n.doc:
- X nro >$*.doc -ms:an $*.n
- X.h.sym:
- X copy $*.h to ram:t/dummy.c
- X lc $(CFLAGS) -ph -o$*.sym ram:t/dummy.c
- X delete ram:t/dummy.c
- X
- X#
- X# Makefile dependencies
- X#
- XOBJS = bbsindex.o checkfiles.o command.o expression.o format.o sort.o
- X
- Xall: bbsindex
- X
- Xbbsindex: $(OBJS) tiny.o
- X blink from $(START) $(OBJS) to bbsindex $(BFLAGS) lib lib:lc.lib
- X
- Xbbsindex.doc: bbsindex.n
- X
- Xsystem.sym: system.h
- Xbbsindex.o: bbsindex.c system.sym bbsindex.h bbs.h
- Xcheckfiles.o: checkfiles.c system.sym bbsindex.h bbs.h
- Xcommand.o: command.c system.sym bbsindex.h bbs.h
- Xexpression.o: expression.c system.sym bbsindex.h bbs.h
- Xformat.o: format.c system.sym bbsindex.h bbs.h
- Xsort.o: sort.c system.sym bbsindex.h bbs.h
- Xtiny.o: tiny.a
- END_OF_FILE
- if test 1075 -ne `wc -c <'src/makefile'`; then
- echo shar: \"'src/makefile'\" unpacked with wrong size!
- fi
- # end of 'src/makefile'
- fi
- if test -f 'src/sort.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/sort.c'\"
- else
- echo shar: Extracting \"'src/sort.c'\" \(3552 characters\)
- sed "s/^X//" >'src/sort.c' <<'END_OF_FILE'
- X/*
- X * SORT.C
- X *
- X * This module contains the sorting routines that read sorting order from
- X * the command line, and sort the file database according to that order.
- X *
- X */
- X
- X#ifndef LATTICE_50
- X#include "system.h"
- X#endif
- X
- X#include "bbsindex.h"
- X
- X
- X/*
- X * Arrays used to determine sorting order for SORT.
- X */
- X
- Xint i_order[MAXINDEX+1];
- Xint i_ascend[MAXINDEX+1];
- X
- X
- X/*
- X * sortcmp()
- X * ---------
- X * This function is called by qsort. It compares the two specified
- X * elements, and returns -ve, 0 or +ve to indicate whether the second
- X * record is greater than, equal or less than the first, using the
- X * sorting criteria defined in SORT.
- X */
- X
- X/*
- X * DOCMP is a macro which sets cmp equal to the value of the enclosed
- X * expression if i_ascend[i] is true, or the negative of the expression
- X * if i_ascend is false.
- X */
- X#define DOCMP(x) (cmp = (i_ascend[i] ? (x) : -(x)))
- Xint sortcmp(ptr1,ptr2)
- XUDHEAD **ptr1, **ptr2;
- X{
- X UDHEAD *p1 = *ptr1, *p2 = *ptr2;
- X int i, cmp = 0;
- X
- X /*
- X * Note safety exit - last element of i_order is guaranteed == I_ANY
- X */
- X for (i = 0; !cmp; i++) {
- X switch (i_order[i]) {
- X
- X case I_ANY: return(0);
- X
- X case I_ACCESS: DOCMP(p1->accesses - p2->accesses);
- X break;
- X case I_BINARY: DOCMP(p2->bin - p1->bin);
- X break;
- X case I_COMMENT: DOCMP(stricmp(p1->desc, p2->desc));
- X break;
- X case I_DISKNAME: DOCMP(stricmp(p1->disk_name, p2->disk_name));
- X break;
- X case I_SECTION: DOCMP(p1->section - p2->section);
- X break;
- X case I_ONLINE: DOCMP(p2->online - p1->online);
- X break;
- X case I_LOCAL: DOCMP(p2->local - p1->local);
- X break;
- X case I_NAME: DOCMP(strcmp(p1->cat_name, p2->cat_name));
- X break;
- X case I_OWNER: DOCMP(strcmp(p1->owner, p2->owner));
- X break;
- X case I_PATHNAME: DOCMP(strcmp(dirnames[p1->dirnum],
- X dirnames[p2->dirnum]));
- X break;
- X case I_DIRECTORY: DOCMP(p1->dir - p2->dir);
- X break;
- X case I_DISKDIRNUM: DOCMP(p1->dirnum - p2->dirnum);
- X break;
- X case I_VALID: DOCMP(p2->valid - p1->valid);
- X break;
- X case I_DATE: DOCMP(p1->date - p2->date);
- X break;
- X case I_SIZE: DOCMP(p1->length - p2->length);
- X break;
- X case I_KSIZE: DOCMP(BTOK(p1->length) - BTOK(p2->length));
- X break;
- X }
- X }
- X return (cmp);
- X}
- X
- X
- X/*
- X * com_sort()
- X * ----------
- X * This command sorts the file database into order, according to
- X * the indexes specified. Each index may be optionally followed by
- X * a + or - to indirect sorting direction (ascending or descending).
- X * There must be no space between the direction and the +/-.
- X */
- Xvoid com_sort()
- X{
- X char *index, *p;
- X int i, j;
- X int ascend;
- X
- X CHECKDATABASE();
- X
- X sorted = TRUE;
- X for (i = 0; i < MAXINDEX && compos < comlen; i++) {
- X index = getstring();
- X p = index + strlen(index) - 1;
- X
- X /*
- X * Now check to see if sorting direction specified, and adjust
- X * string if it was. Set 'ascend' to TRUE if ascending,
- X * else FALSE.
- X */
- X ascend = TRUE;
- X if (*p == CHAR_ASCEND || *p == CHAR_DESCEND) {
- X if (*p == CHAR_DESCEND)
- X ascend = FALSE;
- X *p = CHAR_NULL;
- X }
- X
- X /*
- X * Now match index, and setup appropriate entry in array
- X */
- X
- X for (j = 0; j < MAXINDEX && strcmp(index,indexes[j].name); j++)
- X ;
- X if (j == MAXINDEX) {
- X scripterror("unknown index ");
- X print2(index, "\n");
- X Cleanup(10);
- X }
- X i_order[i] = indexes[j].tag;
- X i_ascend[i] = ascend;
- X }
- X if (i == 0) {
- X i_order[i] = I_NAME;
- X i_ascend[i++] = TRUE;
- X }
- X i_order[i] = I_ANY;
- X
- X /* Finally, do the sort! */
- X qsort(ptrblock, numrecs, sizeof(UDHEAD *), sortcmp);
- X}
- END_OF_FILE
- if test 3552 -ne `wc -c <'src/sort.c'`; then
- echo shar: \"'src/sort.c'\" unpacked with wrong size!
- fi
- # end of 'src/sort.c'
- fi
- if test -f 'src/system.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/system.h'\"
- else
- echo shar: Extracting \"'src/system.h'\" \(191 characters\)
- sed "s/^X//" >'src/system.h' <<'END_OF_FILE'
- X/* Include files for BBSindex */
- X
- X#include <exec/types.h>
- X#include <proto/dos.h>
- X#include <proto/exec.h>
- X#include <proto/intuition.h>
- X#include <ctype.h>
- X#include <string.h>
- X#include <time.h>
- END_OF_FILE
- if test 191 -ne `wc -c <'src/system.h'`; then
- echo shar: \"'src/system.h'\" unpacked with wrong size!
- fi
- # end of 'src/system.h'
- fi
- if test -f 'src/tiny.a' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/tiny.a'\"
- else
- echo shar: Extracting \"'src/tiny.a'\" \(6132 characters\)
- sed "s/^X//" >'src/tiny.a' <<'END_OF_FILE'
- X*:ts=8
- X****************************************************************************
- X* *
- X* TINY.A (C) Copyright Eddy Carroll 1989 *
- X* ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
- X* *
- X* Replacement startup code for Lattice C V5.04. Use instead of c.o *
- X* This has many features stripped out to allow small utilities to have *
- X* as small a filesize as possible. In particular, don't call any of the *
- X* stdio functions. *
- X* *
- X****************************************************************************
- X
- X INCLUDE "exec/types.i"
- X INCLUDE "exec/alerts.i"
- X INCLUDE "exec/nodes.i"
- X INCLUDE "exec/lists.i"
- X INCLUDE "exec/ports.i"
- X INCLUDE "exec/libraries.i"
- X INCLUDE "exec/tasks.i"
- X INCLUDE "libraries/dos.i"
- X INCLUDE "libraries/dosextens.i"
- X INCLUDE "workbench/startup.i"
- X INCLUDE "exec/funcdef.i"
- X INCLUDE "exec/exec_lib.i"
- X INCLUDE "libraries/dos_lib.i"
- X
- XMAXARGS EQU 100 ; Maximum number of command line arguments from CLI
- XAbsExecBase EQU 4 ; Welcome to the only fixed point in the universe
- X
- X* A useful macro to let us call library routines
- Xcallsys macro
- X CALLLIB _LVO\1
- X endm
- X
- X xdef XCEXIT
- X xdef exit
- X xref LinkerDB
- X xref _BSSBAS
- X xref _BSSLEN
- X
- X csect text,0,0,1,2 * xref's after this are 16-bit reloc
- X xref main * Name of C program to start with.
- X
- Xstart:
- X movem.l d1-d6/a0-a6,-(a7)
- XREGSIZE EQU (6+7)*4
- X lea REGSIZE(a7),A5 * Determine old stack pointer
- X move.l a0,a2 * Save command pointer
- X move.l d0,d2 * and command length
- X lea LinkerDB,a4 * Load base register
- X
- X move.l AbsExecBase.W,a6
- X move.l a6,SysBase(A4)
- X move.l a7,_StackPtr(A4) * Save stack ptr
- X
- X suba.l a1,a1
- X callsys FindTask * Find out our task ID
- X move.l d0,a3
- X
- X move.l a5,D0 * get top of stack
- X sub.l 4(a5),D0 * compute bottom
- X add.l #128,D0 * allow for parms overflow
- X move.l D0,_base(A4) * save for stack checking
- X
- X lea DOSName(A4),A1
- X moveq.l #0,D0
- X callsys OpenLibrary
- X move.l D0,DOSBase(A4)
- X bne getcom
- XnoDOS:
- X moveq.l #100,d0
- X bra exit2
- X
- X*------ find command name:
- Xgetcom:
- X move.l pr_CLI(a3),a0
- X add.l a0,a0
- X add.l a0,a0
- X move.l cli_CommandName(a0),a1
- X add.l a1,a1
- X add.l a1,a1
- X
- X*------ collect parameters:
- X move.l d2,d0 * get command line length
- X moveq.l #0,d1
- X move.b (a1)+,d1
- X move.l a1,_ProgramName(A4)
- X add.l d1,d0 * add length of command name
- X addq.l #1,d0 * allow for space after command
- X
- X clr.w -(A7) * set null terminator for command line
- X addq.l #1,D0 * force to even number of bytes
- X andi.w #$fffe,D0 * (round up)
- X sub.l D0,A7 * make room on stack for command line
- X subq.l #2,D0
- X clr.w 0(A7,D0)
- X
- X*------ copy command line onto stack
- X move.l d2,d0 * get command line length
- X subq.l #1,d0
- X add.l d1,d2
- X
- Xcopy_line:
- X move.b 0(A2,D0.W),0(A7,D2.W) * copy command line to stack
- X subq.l #1,d2
- X dbf d0,copy_line
- X move.b #' ',0(a7,d2.w) * add space between command and parms
- X subq.l #1,d2
- X
- Xcopy_cmd:
- X move.b 0(a1,d2.w),0(a7,d2.w) * copy command name to stack
- X dbf d2,copy_cmd
- X move.l a7,a1 * Get pointer to new command line
- X
- X sub.l #(MAXARGS*4),a7 * Reserve space for argv[]
- X move.l a7,a2 * Initialise base into array
- X move.l a2,a3 * Save base of argv
- X moveq #0,d2 * Initialise argc
- X
- X*
- X* From here on down, A1 is pointer into command line
- X*
- Xbuild_argv:
- X bsr.s getnext * Read next character from line
- X bcs.s doquote * If quote, handle
- X beq.s build_argv * If white space, skip over it
- X
- X lea -1(a1),a0 * Get address of this parameter
- X bsr.s bumpargv * Store it to argv[] array
- Xbuild_2:
- X bsr.s getnext * Get next character
- X bne.s build_2 * If not white space, keep looking
- X clr.b -1(a1) * Zero-terminate current argument
- X bra.s build_argv * And go back to get next argument
- X
- Xdoquote:
- X move.l a1,a0 * Get pointer to this argument
- X bsr.s bumpargv * Output it to argv[]
- Xquote_2:
- X bsr.s getnext * Get next character
- X bcc.s quote_2 * If not quote, keep looking
- X clr.b -1(a1) * Zero-terminate current argument
- Xquote_3:
- X bsr.s getnext * Get next character
- X bne.s quote_3 * Skip until space reached
- X beq.s build_argv * Go back and read next argument
- X
- Xbumpargv:
- X move.l a0,(a2)+ * Output ptr to current argument
- X addq #1,d2 * Increment argc
- X cmpi #MAXARGS,d2 * Used up all our arguments yet?
- X bls.s qrts * If not, then return
- X moveq #110,d0 * Else set return code
- X bra.s exit2 * And exit
- X
- X*
- X* Reads next character from command line. If zero, never returns, but
- X* drops into call to main. Else, returns, with C=1 if character is quote,
- X* Z=1 if character is white space.
- X*
- Xgetnext:
- X move.b (a1)+,d0 * Get character from command line
- X beq.s get_2 * Exit if end of line
- X cmp.b #34,d0 * Check if quote
- X beq.s isquote *
- X cmp.b #32,d0 * Check if space
- X beq.s isspace *
- X cmp.b #9,d0 * Or tab
- X beq.s isspace *
- X cmp.b #10,d0 * Or end of line
- Xisspace:
- X andi #$1E,ccr * Clear carry flag, retaining Z
- Xqrts rts
- X
- Xisquote:
- X ori #1,ccr * Set carry flag
- X andi #$FB,ccr * Clear zero flag
- X rts * And return
- X
- Xget_2:
- X move.l a3,-(a7) * Push argv onto stack
- X move.l d2,-(a7) * Push argc onto stack
- X
- X lea _BSSBAS,a3 * get base of BSS
- X moveq #0,d1
- X move.l #_BSSLEN,d0 * get length of BSS in longwords
- X bra.s clr_lp * and clear for length given
- Xclr_bss move.l d1,(a3)+
- Xclr_lp dbf d0,clr_bss
- X
- Xdomain:
- X jsr main(PC) * Call main(argc,argv)
- X moveq.l #0,d0 * Set successful status
- X bra.s exit2
- X
- Xexit:
- X_exit:
- XXCEXIT:
- X move.l 4(SP),d0 * Extract return code
- Xexit2:
- X move.l d0,-(a7)
- X move.l AbsExecBase.W,a6
- X move.l DOSBase(A4),a1
- X callsys CloseLibrary * Close Dos library
- X
- X*------ this rts sends us back to DOS:
- XexitToDOS:
- X MOVE.L (A7)+,D0
- X movea.l _StackPtr(a4),SP * Restore stack ptr
- X movem.l (a7)+,d1-d6/a0-a6
- X rts
- X
- X*-----------------------------------------------------------------------
- X* Global definitions
- X*
- X csect __MERGED,1,,2,2
- X
- X xdef NULL,SysBase,LoadAddress,DOSBase
- X xdef _oserr,_OSERR,_ONBREAK
- X xdef _ProgramName,_StackPtr,_base
- X
- XNULL dc.l 0
- X_base dc.l 0
- X_oserr equ *
- X_OSERR dc.l 0
- X_ONBREAK dc.l 0
- XSysBase dc.l 0
- XLoadAddress dc.l 0
- X_StackPtr dc.l 0
- XDOSBase dc.l 0
- X_ProgramName dc.l 0
- XDOSName dc.b 'dos.library',0
- X
- X END
- END_OF_FILE
- if test 6132 -ne `wc -c <'src/tiny.a'`; then
- echo shar: \"'src/tiny.a'\" unpacked with wrong size!
- fi
- # end of 'src/tiny.a'
- fi
- echo shar: End of archive 1 \(of 3\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
- amiga@cs.odu.edu
- or amiga@xanth.cs.odu.edu ( obsolescent mailers may need this address )
- or ...!uunet!xanth!amiga ( very obsolescent mailers need this address )
-
- Comments, questions, and suggestions s should be addressed to ``amiga-request''
- (only use ``amiga'' for submissions) at the above addresses.
-